#pragma once

#include "car_sprint_game.hpp"
#include <eosiolib/asset.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/transaction.hpp>
#include <string>

namespace eosio {
   using std::string;

   class rainbow : public contract {
      private:
         /// @abi table userinfo i64
         struct userinfo {
            uint64_t       id;
            account_name   name;                      //账号
            uint64_t       regtime;                   //注册时间
            uint64_t       lastlogin;                 //最后登录时间
            asset          totalbet;                  //总下注数
            asset          rewarded_amount;           //奖励总数
            asset          pledgerab;                 //质押的RAB
            asset          dividend;                  //可领取的分红
            uint16_t       failcount;                 //异常次数
            uint64_t       referrer_id;               //推荐人账号
            uint64_t primary_key() const { return id; }
            account_name get_name() const { return name; }
            EOSLIB_SERIALIZE( userinfo, (id)(name)(regtime)(lastlogin)(totalbet)(rewarded_amount)(pledgerab)(dividend)(failcount)(referrer_id) )
         };

         typedef eosio::multi_index<N(userinfo), userinfo
                 , indexed_by< N(byname), const_mem_fun<userinfo, account_name, &userinfo::get_name> >
                 > users;

         users user_table;

         /// @abi table raise i64
         struct raise {
            //筹集EOS兑换RAB
            uint64_t       id;
            uint64_t       userid;
            asset          eos_amount;             //消耗EOS
            asset          token_amount;           //获得RAB
            asset          raise_amount;           //筹集总消耗EOS
            uint64_t       createtime;
            uint64_t primary_key() const { return id; }
            EOSLIB_SERIALIZE( raise, (id)(userid)(eos_amount)(token_amount)(raise_amount)(createtime) )
         };

         typedef eosio::multi_index<N(raise), raise> raises;

         raises raise_table;

         /// @abi table other i64
         struct other {
            //分红池
            uint32_t id;
            asset    amount;           //分红池总数
            asset    mining;           //挖矿总数
            asset    raiserab;         //总通过募集获得的RAB数
            asset    raiseeos;         //总募集到的EOS
            uint8_t  isopen;           //游戏开关     0：关闭  1：开启
            uint8_t  canraise;         //是否可募集   0：关闭   1：开启
            uint64_t updatetime;
            uint64_t primary_key() const { return id; }
            EOSLIB_SERIALIZE( other, (id)(amount)(mining)(raiserab)(raiseeos)(isopen)(canraise)(updatetime) )
         };

         typedef eosio::multi_index< N(other), other > others;

         others other_table;

         /// @abi table tranlist i64
         struct tranlist {
            uint64_t       id;
            account_name   fromname;      //转账方用户
            uint64_t       from;          //转账方用户ID，如果是本合约账户，则ID为0
            uint64_t       to;            //转账接收方用户ID
            asset          quantity;      //金额
            std::string    memo;          //备注
            uint64_t       confirm;       //是否确认        0：未处理  1：已处理   2：异常交易
            std::string    txid;          //当前交易的ID
            uint64_t       type;          //交易类型 0：其他  1：募集  2：质押RAB  3：赛车游戏下注  4：挖矿奖励  5：推荐奖励 6：募集RAB 7：下注满1000，返还  80：赛车游戏中奖奖金
            std::string    gameinfo;      //游戏的专用信息
            uint64_t       createtime;    //创建时间
            uint64_t primary_key() const { return id; }
            uint64_t get_from() const { return from; }
            uint64_t get_confirm() const { return confirm; }
            uint64_t get_type() const { return type; }

            EOSLIB_SERIALIZE( tranlist, (id)(fromname)(from)(to)(quantity)(memo)(confirm)(txid)(type)(gameinfo)(createtime) )
         };

         typedef eosio::multi_index< N(tranlist), tranlist
                  , indexed_by< N(byfrom), const_mem_fun<tranlist, uint64_t, &tranlist::get_from> >
                  , indexed_by< N(byconfirm), const_mem_fun<tranlist, uint64_t, &tranlist::get_confirm> >
                  , indexed_by< N(bytype), const_mem_fun<tranlist, uint64_t, &tranlist::get_type> >
                  > tranlists;

         tranlists tranlist_table;

         void issue( account_name to, asset quantity, string memo );

         void execRaise( account_name name, asset quantity, uint64_t tran_id );

         void save_bet( account_name name, asset quantity );

         uint64_t getUserId( account_name name );

         asset getExchangeRab( asset quantity, asset lastTotal );

         void addDividend( asset quantity );

         account_name getUserName( uint64_t userid );

         void save_transfer( account_name from, account_name to, asset quantity, string memo, uint64_t type, std::string gameinfo );

         bool isCanRaise();

         void cumulativebet( uint64_t userid, asset quantity, account_name from );

         void betReward( uint64_t referrer_id, account_name from, asset quantity );

         void mining( asset quantity, uint64_t userid );

         void runTransaction( uint64_t tran_id );

         void settlement( uint8_t gametype, uint64_t gameid );

         void check();

         uint64_t login( account_name name, account_name referrer );

         uint64_t addUser( account_name name, account_name referrer );
         car_sprint_game *car;
      public:
         rainbow( account_name self ):contract(self),
                  tranlist_table(self, self),
                  user_table(self, self),
                  other_table(self, self),
                  raise_table(self, self) {
            car = new car_sprint_game(_self);
         }

         /// @abi action
         void setup( uint8_t gameswitch, uint8_t canraise );

         /// @abi action
         void transfer( account_name from, account_name to, asset quantity, string memo );

         /// @abi action
         void checktx( uint64_t tran_id, uint8_t type );
   };
} /// namespace eosio